home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 1.iso
/
toolbox
/
src
/
exampleCode
/
opengl
/
GLUT
/
progs
/
examples
/
zoomdino.c
< prev
Wrap
C/C++ Source or Header
|
1996-11-11
|
13KB
|
467 lines
/* Copyright (c) Mark J. Kilgard, 1994. */
/* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */
/* zoomdino demonstrates GLUT 3.0's new overlay support. Both
rubber-banding the display of a help message use the overlays. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h> /* for cos(), sin(), and sqrt() */
#include <GL/glu.h>
#include <GL/glut.h>
typedef enum {
RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
} displayLists;
GLfloat angle = -150; /* in degrees */
GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
int moving, begin;
int W = 300, H = 300;
GLdouble bodyWidth = 2.0;
int newModel = 1;
/* *INDENT-OFF* */
GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
{11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
{8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
{1, 2} };
GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
{15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
{13, 9}, {11, 11}, {9, 11} };
GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
{12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
{9.6, 15.25}, {9, 15.25} };
GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0}; /* red-tinted */
GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
int overlaySupport, red, white, transparent, rubberbanding;
int anchorx, anchory, stretchx, stretchy, pstretchx, pstretchy;
float vx, vy, vx2, vy2, vw, vh;
float wx, wy, wx2, wy2, ww, wh;
int fancy, wasFancy, help, clearHelp;
/* *INDENT-ON* */
void
extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
{
static GLUtriangulatorObj *tobj = NULL;
GLdouble vertex[3], dx, dy, len;
int i;
int count = dataSize / (2 * sizeof(GLfloat));
if (tobj == NULL) {
tobj = gluNewTess(); /* create and initialize a GLU
polygontesselation object */
gluTessCallback(tobj, GLU_BEGIN, glBegin);
gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky
*/
gluTessCallback(tobj, GLU_END, glEnd);
}
glNewList(side, GL_COMPILE);
glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
tessellation */
gluBeginPolygon(tobj);
for (i = 0; i < count; i++) {
vertex[0] = data[i][0];
vertex[1] = data[i][1];
vertex[2] = 0;
gluTessVertex(tobj, vertex, data[i]);
}
gluEndPolygon(tobj);
glEndList();
glNewList(edge, GL_COMPILE);
glShadeModel(GL_FLAT); /* flat shade keeps angular hands
from being "smoothed" */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= count; i++) {
/* mod function handles closing the edge */
glVertex3f(data[i % count][0], data[i % count][1], 0.0);
glVertex3f(data[i % count][0], data[i % count][1], thickness);
/* Calculate a unit normal by dividing by Euclidean
distance. We could be lazy and use
glEnable(GL_NORMALIZE) so we could pass in arbitrary
normals for a very slight performance hit. */
dx = data[(i + 1) % count][1] - data[i % count][1];
dy = data[i % count][0] - data[(i + 1) % count][0];
len = sqrt(dx * dx + dy * dy);
glNormal3f(dx / len, dy / len, 0.0);
}
glEnd();
glEndList();
glNewList(whole, GL_COMPILE);
glFrontFace(GL_CW);
glCallList(edge);
glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
glCallList(side);
glPushMatrix();
glTranslatef(0.0, 0.0, thickness);
glFrontFace(GL_CCW);
glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
glCallList(side);
glPopMatrix();
glEndList();
}
void
makeDinosaur(void)
{
GLfloat bodyWidth = 3.0;
extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
BODY_SIDE, BODY_EDGE, BODY_WHOLE);
extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
ARM_SIDE, ARM_EDGE, ARM_WHOLE);
extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
LEG_SIDE, LEG_EDGE, LEG_WHOLE);
extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
EYE_SIDE, EYE_EDGE, EYE_WHOLE);
glNewList(DINOSAUR, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
glCallList(BODY_WHOLE);
glPushMatrix();
glTranslatef(0.0, 0.0, bodyWidth);
glCallList(ARM_WHOLE);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
glCallList(ARM_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth / 4);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
glCallList(EYE_WHOLE);
glPopMatrix();
glEndList();
}
void
recalcModelView(void)
{
glPopMatrix();
glPushMatrix();
glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(-8, -8, -bodyWidth / 2);
newModel = 0;
}
void
redraw(void)
{
if (newModel)
recalcModelView();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCallList(DINOSAUR);
glutSwapBuffers();
}
void
output(int x, int y, char *string)
{
int len, i;
glRasterPos2f(x, y);
len = (int) strlen(string);
for (i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, string[i]);
}
}
char *helpMsg[] =
{
"Welcome to zoomdino!",
" Left mouse button rotates",
" the dinosaur.",
" Middle mouse button zooms",
" via overlay rubber-banding.",
" Right mouse button shows",
" pop-up menu.",
" To reset view, use \"Reset",
" Projection\".",
"(This message is in the overlays.)",
NULL
};
void
redrawOverlay(void)
{
if (help) {
int i;
glClear(GL_COLOR_BUFFER_BIT);
glIndexi(white);
for (i = 0; helpMsg[i]; i++) {
output(15, 24 + i * 18, helpMsg[i]);
}
return;
}
if (glutLayerGet(GLUT_OVERLAY_DAMAGED) || clearHelp) {
/* Opps, damage means we need a full clear. */
glClear(GL_COLOR_BUFFER_BIT);
clearHelp = 0;
wasFancy = 0;
} else {
/* Goody! No damage. Just erase last rubber-band. */
if (fancy || wasFancy) {
glLineWidth(3.0);
}
glIndexi(transparent);
glBegin(GL_LINE_LOOP);
glVertex2i(anchorx, anchory);
glVertex2i(anchorx, pstretchy);
glVertex2i(pstretchx, pstretchy);
glVertex2i(pstretchx, anchory);
glEnd();
}
if (wasFancy) {
glLineWidth(1.0);
wasFancy = 0;
}
if (fancy)
glLineWidth(3.0);
glIndexi(red);
glBegin(GL_LINE_LOOP);
glVertex2i(anchorx, anchory);
glVertex2i(anchorx, stretchy);
glVertex2i(stretchx, stretchy);
glVertex2i(stretchx, anchory);
glEnd();
if (fancy) {
glLineWidth(1.0);
glIndexi(white);
glBegin(GL_LINE_LOOP);
glVertex2i(anchorx, anchory);
glVertex2i(anchorx, stretchy);
glVertex2i(stretchx, stretchy);
glVertex2i(stretchx, anchory);
glEnd();
}
glFlush();
/* Remember last place rubber-banded so the rubber-band can
be erased next redisplay. */
pstretchx = stretchx;
pstretchy = stretchy;
}
void
defaultProjection(void)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
vx = -1.0;
vw = 2.0;
vy = -1.0;
vh = 2.0;
glFrustum(vx, vx + vw, vy, vy + vh, 1.0, 40);
glMatrixMode(GL_MODELVIEW);
}
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
moving = 1;
begin = x;
} else if (state == GLUT_UP) {
glutSetCursor(GLUT_CURSOR_INHERIT);
moving = 0;
}
}
if (overlaySupport && button == GLUT_MIDDLE_BUTTON) {
if (state == GLUT_DOWN) {
help = 0;
clearHelp = 1;
rubberbanding = 1;
anchorx = x;
anchory = y;
stretchx = x;
stretchy = y;
glutShowOverlay();
} else if (state == GLUT_UP) {
rubberbanding = 0;
glutHideOverlay();
glutUseLayer(GLUT_NORMAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))
wx = min(anchorx, stretchx);
wy = min(H - anchory, H - stretchy);
wx2 = max(anchorx, stretchx);
wy2 = max(H - anchory, H - stretchy);
ww = wx2 - wx;
wh = wy2 - wy;
if (ww == 0 || wh == 0) {
glutUseLayer(GLUT_NORMAL);
defaultProjection();
} else {
vx2 = wx2 / W * vw + vx;
vx = wx / W * vw + vx;
vy2 = wy2 / H * vh + vy;
vy = wy / H * vh + vy;
vw = vx2 - vx;
vh = vy2 - vy;
glFrustum(vx, vx + vw, vy, vy + vh, 1.0, 40);
}
glutPostRedisplay();
glMatrixMode(GL_MODELVIEW);
}
}
}
void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - begin);
begin = x;
newModel = 1;
glutPostRedisplay();
}
if (rubberbanding) {
stretchx = x;
stretchy = y;
glutPostOverlayRedisplay();
}
}
void
reshape(int w, int h)
{
if (overlaySupport) {
glutUseLayer(GLUT_OVERLAY);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, 0, h);
glScalef(1, -1, 1);
glTranslatef(0, -h, 0);
glMatrixMode(GL_MODELVIEW);
glutUseLayer(GLUT_NORMAL);
}
glViewport(0, 0, w, h);
W = w;
H = h;
}
GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
void
controlLights(int value)
{
glutUseLayer(GLUT_NORMAL);
switch (value) {
case 1:
lightZeroSwitch = !lightZeroSwitch;
if (lightZeroSwitch) {
glEnable(GL_LIGHT0);
} else {
glDisable(GL_LIGHT0);
}
break;
case 2:
lightOneSwitch = !lightOneSwitch;
if (lightOneSwitch) {
glEnable(GL_LIGHT1);
} else {
glDisable(GL_LIGHT1);
}
break;
case 3:
defaultProjection();
break;
case 4:
fancy = 1;
break;
case 5:
fancy = 0;
wasFancy = 1;
break;
case 6:
if (!rubberbanding)
help = 1;
glutShowOverlay();
glutPostOverlayRedisplay();
break;
}
glutPostRedisplay();
}
int
main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("zoomdino");
glutDisplayFunc(redraw);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutCreateMenu(controlLights);
glutAddMenuEntry("Toggle right light", 1);
glutAddMenuEntry("Toggle left light", 2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
makeDinosaur();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
defaultProjection();
gluLookAt(0.0, 0.0, 30.0, /* eye is at (0,0,30) */
0.0, 0.0, 0.0, /* center is at (0,0,0) */
0.0, 1.0, 0.); /* up is in postivie Y direction */
glPushMatrix(); /* dummy push so we can pop on model
recalc */
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glutInitDisplayMode(GLUT_SINGLE | GLUT_INDEX);
overlaySupport = glutLayerGet(GLUT_OVERLAY_POSSIBLE);
if (overlaySupport) {
glutEstablishOverlay();
glutHideOverlay();
transparent = glutLayerGet(GLUT_TRANSPARENT_INDEX);
glClearIndex(transparent);
red = (transparent + 1) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
white = (transparent + 2) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
glutSetColor(red, 1.0, 0.0, 0.0); /* Red. */
glutSetColor(white, 1.0, 1.0, 1.0); /* White. */
glutOverlayDisplayFunc(redrawOverlay);
glutReshapeFunc(reshape);
glutSetWindowTitle("zoomdino with rubber-banding");
glutAddMenuEntry("------------------", 0);
glutAddMenuEntry("Reset projection", 3);
glutAddMenuEntry("------------------", 0);
glutAddMenuEntry("Fancy rubber-banding", 4);
glutAddMenuEntry("Simple rubber-banding", 5);
glutAddMenuEntry("------------------", 0);
glutAddMenuEntry("Show help", 6);
} else {
printf("Sorry, no whizzy zoomdino overlay usage!\n");
}
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}